#include "mypthread.hpp"

// 单例模式线程池

template <class T>
class pthreadpool
{
public:
    void push_task(const T &tmp)
    {
        log(DEBUG, "push_task start run");
        lock();
        if (_run)
        {
            _que.push(tmp);
            if (_wait_sum > 0)
            {
                queue_wakeup();
            }
        }
        unlock();
        return;
    }

    static pthreadpool<T>* getpoool()
    {
        if(_pool == nullptr)
        {
            pthread_mutex_lock(&_singleton_mutex);
            _pool = new pthreadpool<T>();
            _pool->pthreadpool_init();
            _pool->pool_run();
            log(DEBUG,"创建线程池");
            pthread_mutex_unlock(&_singleton_mutex);
        }
        else
        {
            log(DEBUG,"获取线程池");
        }
        return _pool;
    }

    ~pthreadpool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    pthreadpool(const pthreadpool<T>& pool) = delete;
    pthreadpool<T>& operator=(const pthreadpool<T>& pool) = delete;
    
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void queue_sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void queue_wakeup()
    {
        pthread_cond_signal(&_cond);
    }

    void queue_wakeup_all()
    {
        pthread_cond_broadcast(&_cond);
    }

    pthreadpool(int num = 5) : _num(num), _wait_sum(0), _run(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    static void pthread_run(void *tmp)
    {
        log(DEBUG, "pthread_run start run");
        pthreadpool<T> *_this = static_cast<pthreadpool<T> *>(tmp);
        while (1)
        {
            _this->lock();

            // 如果线程是正常运行但是任务队列没有数据
            while (_this->_run && _this->_que.empty())
            {
                _this->_wait_sum++;
                _this->queue_sleep();
                _this->_wait_sum--;
            }

            // 如果线程池不是正常运行并且任务队列中没有数据
            if (!_this->_run && _this->_que.empty())
            {
                _this->unlock();
                log(DEBUG, "pthread_run exit");
                return;
            }

            // 1, 如果线程正常运行并且有数据
            // 2, 线程不正常运行但是有数据
            T t = _this->_que.front();
            _this->_que.pop();
            _this->unlock();

            srand((unsigned int)time(nullptr));
            // 执行任务
            int ret = 0;
            ret = t();
            cout << ret << endl;
        }
    }

    void pthreadpool_init()
    {
        log(DEBUG, "pthread_init start run");
        for (int i = 0; i < _num; i++)
        {
            string name = "pthread-" + to_string(i);
            _v.emplace_back(name, pthread_run, this);
        }
    }

    void pool_run()
    {
        _run = true;
        log(DEBUG, "Pool_run start run");
        for (auto &e : _v)
        {
            e.start();
        }        
    }

    void stop()
    {
        lock();
        _run = false;
        queue_wakeup_all();
        unlock();
    }

    bool _run;     // 是否运行
    int _wait_sum; // 等待的线程有多少
    int _num;      // 线程的数量

    vector<mypthread> _v;   // 线程池
    queue<T> _que;          // 任务队列
    pthread_mutex_t _mutex; // 锁
    pthread_cond_t _cond;   // 条件变量

    static pthreadpool<T>* _pool;
    static pthread_mutex_t _singleton_mutex;
};

template<class T>
pthreadpool<T>* pthreadpool<T>::_pool = nullptr;

template<class T>
pthread_mutex_t pthreadpool<T>::_singleton_mutex = PTHREAD_MUTEX_INITIALIZER;